/* Includes ------------------------------------------------------------------*/
#include <main.h>

/* Private define-------------------------------------------------------------*/
#define FUNCTIONCODE_READ_REGISTER      0x03    //读保持寄存器功能码
#define FUNCTIONCODE_WRITE_REGISTER     0x06    //写保持寄存器功能码
/* Private variables----------------------------------------------------------*/
static void Protocol_Analysis(UART_t* );        //协议分析
static void Modbus_Read_Register(UART_t* );     //读保持寄存器
static void Modbus_Write_Register(UART_t* );    //写保持寄存器
/* Public variables-----------------------------------------------------------*/
Modbus_t idata Modbus = 
{
    1,

    Protocol_Analysis,
};
/* Private function prototypes------------------------------------------------*/

/*
* @name   Potocol_Analysis
* @brief  协议分析
* @param  UART：指向串口的指针
* @retval None   
*/
static void Protocol_Analysis(UART_t* UART) //因为要用到串口接收和发送数组，所以参数定义结构体指针
{
    UART_t* const xdata COM = UART;

    //喂狗
    WatchDog.Feed();

    //计算CRC_16
    //收到8个字节数据后先算出前6个字节的CRC校验码
    CRC_16.CRC = CRC_16.CRC_Check(COM->pucRec_Buffer,6);
    CRC_16.CRC_H = (uint8_t)(CRC_16.CRC >> 8);  //得到CRC校验值的高8位
    CRC_16.CRC_L = (uint8_t)CRC_16.CRC;         //得到CRC校验值的低8位

    //校验CRC_16
    //有些数据CRC_16校验的高位在前，低位在后，也有些是低位在前，高位在后的，所以两种情况都要判断
    if(((*(COM->pucRec_Buffer+6) == CRC_16.CRC_L) && (*(COM->pucRec_Buffer+7) == CRC_16.CRC_H))
    ||
    ((*(COM->pucRec_Buffer+6) == CRC_16.CRC_H) && (*(COM->pucRec_Buffer+7) == CRC_16.CRC_L)))
    {
        //校验从机地址
        if(*(COM->pucRec_Buffer+0) == Modbus.Addr)
        {
            //处理数据
            if(*(COM->pucRec_Buffer+1) == FUNCTIONCODE_READ_REGISTER)
            {
                //读保持寄存器，从机响应并回复数据
                Modbus_Read_Register(COM);
            }
            else if(*(COM->pucRec_Buffer+1) == FUNCTIONCODE_WRITE_REGISTER)
            {
                //写保持寄存器
                Modbus_Write_Register(COM);
            }
        }
    }
    else    //CRC校验码出错
    {
        #ifdef Monitor_Run_Code
            printf("Modbus-RTU CRC check error!\r\n");
        #endif
    }
}

/*
* @name   Modbus_Read_Register
* @brief  主机发送功能码03读保持寄存器，从机响应并回复信息帧
* @param  UART：指向串口的指针
* @retval None   
*/
static void Modbus_Read_Register(UART_t* UART)
{
    UART_t* const xdata COM = UART;

    //喂狗
    WatchDog.Feed();

    //从机回应数据，根据Modbus协议从机返回的信息帧格式填入数据，最后通过串口发送即可
    //地址码
    *(COM->pucSend_Buffer+0) = Modbus.Addr;
    //功能码
    *(COM->pucSend_Buffer+1) = FUNCTIONCODE_READ_REGISTER;
    //数据长度
    *(COM->pucSend_Buffer+2) = 4;   //16位的PCB板温度值和16位的PWM灯亮度值，共32位，即4个字节
    //数据（PCB温度值）
    *(COM->pucSend_Buffer+3) = 0;
    *(COM->pucSend_Buffer+4) = NTC.uTemperature;
    //数据（PWM灯亮度值）
    *(COM->pucSend_Buffer+5) = 0;
    *(COM->pucSend_Buffer+6) = PWM.Duty;
    //CRC校验码
    CRC_16.CRC = CRC_16.CRC_Check(COM->pucSend_Buffer,7);   //计算出前面放入的7个字节数据的CRC校验码
    CRC_16.CRC_H = (uint8_t)(CRC_16.CRC >> 8);
    CRC_16.CRC_L = (uint8_t)CRC_16.CRC;

    *(COM->pucSend_Buffer+7) = CRC_16.CRC_L;     //低位在前
    *(COM->pucSend_Buffer+8) = CRC_16.CRC_H;     //高位在后

    //发送数据
    UART1.UART_SendArray(COM->pucSend_Buffer,9);
}   

/*
* @name   Modbus_Write_Register
* @brief  主机发送功能码06写保持寄存器，从机响应并回复相同的信息帧，并将PWM数据提取出来设置占空比
* @param  UART：指向串口的指针
* @retval None   
*/
static void Modbus_Write_Register(UART_t* UART)
{
    UART_t* const xdata COM =  UART;
    uint8_t i = 0;

    //喂狗
    WatchDog.Feed();
    
    //从机回应数据，因为主机是写保持寄存器，所以从机返回的数据与主机发来的数据一致
    //只要把从机接收到的信息帧再放到发送数组中发送回去就行
    for(i=0;i<8;i++)
    {
        *(COM->pucSend_Buffer+i) = *(COM->pucRec_Buffer+i);
    }
    //发送数据
    UART1.UART_SendArray(COM->pucSend_Buffer,8);

    //提取数据，主机只能发送设置PWM值的数据，所以提取的是PWM的值
    //先验证地址，因为实验的PCB板温度和PWM灯亮度是放在两个不同的地址的
    //40001 ->  PCB板温度
    //40002 ->  PWM灯亮度
    if((*(COM->pucRec_Buffer+2) == 0x9C) && (*(COM->pucRec_Buffer+3) == 0x42))//地址40002 = 0x9C42
    {
        PWM.Duty = *(COM->pucRec_Buffer+5);

        //设置占空比，调整亮度
        PWM.PWM_Duty_Set(PWM.Duty);
        //备份占空比
        PWM.IAP_Duty_Backup(IAP_PWM_DUTY_ADDR,PWM.Duty);
    }
}
/********************************************************
  End Of File
********************************************************/